<?php

namespace Tests\Unit;

use Tests\TestCase;
use App\Models\Bookmark;
use App\Repositories\BookmarkRepository;
use App\Exceptions\Bookmark\CreateBookmarkErrorException;
use App\Exceptions\Bookmark\UpdateBookmarkErrorException;
use App\Exceptions\Bookmark\BookmarkNotFoundException;

class BookmarkRepositoryTest extends TestCase
{
    /**
     * @test
     * @dataProvider bookmarkProvider
     */
    public function canCreateABookmark($data)
    {
        $repository = new BookmarkRepository(new Bookmark);
        $bookmark = $repository->create($data);

        $this->assertInstanceOf(Bookmark::class, $bookmark);
        $this->assertEquals($data['title'], $bookmark->title);
        $this->assertEquals($data['description'], $bookmark->description);
        $this->assertEquals($data['url'], $bookmark->url);
    }

    /**
     * @test
     */
     public function canShowABookmark()
     {
         $bookmark = factory(Bookmark::class)->create();
         $repository = new BookmarkRepository(new Bookmark);
         $found = $repository->find($bookmark->id);

         $this->assertInstanceOf(Bookmark::class, $found);
         $this->assertEquals($found->title, $bookmark->title);
         $this->assertEquals($found->description, $bookmark->description);
         $this->assertEquals($found->url, $bookmark->url);
     }

     /**
      * @test
      */
     public function canShowAllBookmarks()
     {
         $bookmarks = factory(Bookmark::class, 10)->create();
         $repository = new BookmarkRepository(new Bookmark);
         $allFound = $repository->all();

         $this->assertEquals($bookmarks->toArray(), $allFound->toArray());
     }

    /**
     * @test
     * @dataProvider bookmarkProvider
     */
    public function canUpdateABookmark($data)
    {
        $bookmark = factory(Bookmark::class)->create();
        $repository = new BookmarkRepository($bookmark);
        $update = $repository->update($data, $bookmark->id);
        $updated = $repository->find($bookmark->id);

        $this->assertTrue($update);
        $this->assertEquals($data['title'], $updated->title);
        $this->assertEquals($data['description'], $updated->description);
        $this->assertEquals($data['url'], $updated->url);
     }

    /**
     * @test
     */
    public function canDeleteABookmark()
    {
        $bookmark = factory(Bookmark::class)->create();
        $repository = new BookmarkRepository($bookmark);
        $isDeleted = $repository->delete($bookmark->id);

        $this->assertTrue($isDeleted);
    }

    /**
     * @test
     */
    public function shouldThrowAnErrorWhenRequiredFieldsAreMissing()
    {
        $this->expectException(CreateBookmarkErrorException::class);

        $repository = new BookmarkRepository(new Bookmark);
        $repository->create([]);
    }

    /**
     * @test
     */
    public function shouldThrowAnErrorWhenBookmarkIsNotFound()
    {
        $this->expectException(BookmarkNotFoundException::class);

        $repository = new BookmarkRepository(new Bookmark);
        $repository->find(1);
    }

    /**
     * @test
     */
    public function shouldThrowAnExceptionIfUpdateFails()
    {
        $this->expectException(UpdateBookmarkErrorException::class);

        $bookmark = factory(Bookmark::class)->create();
        $repository = new BookmarkRepository($bookmark);
        $data = ['title' => null];
        $repository->update($data, $bookmark->id);
    }


    /**
     * @test
     */
    public function shouldReturnNullWhenDeletingANonExistingBookmark()
    {
        $repository = new BookmarkRepository(new Bookmark);
        $isDeleted = $repository->delete(1);

        $this->assertNull($isDeleted);
    }

     public function bookmarkProvider()
     {
         return [
             [
                 [
                     'title' => 'test',
                     'description' => 'string',
                     'url' => 'https://example.com',
                 ]
             ]
         ];
     }

}
